﻿using AForge.Imaging.Filters;
using Canon;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Repository;
using EDSDKLib;
using Kaliko.ImageLibrary;
using Kaliko.ImageLibrary.Filters;
using Kaliko.ImageLibrary.Scaling;
using Karbel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using Trimmer.Utility;

namespace Trimmer
{
    public partial class Seri : XtraForm
    {
        public Seri()
        {
            InitializeComponent();
        }

        SDKHandler CameraHandler;
        void Seri_FormClosing(object sender, FormClosingEventArgs e)
        {
            CloseSession();
            CameraHandler.Dispose();
        }

        void CameraHandler_CameraHasShutdown(object sender, EventArgs e)
        {
            CloseSession();
        }

        private void CloseSession()
        {
            CameraHandler.CloseSession();
        }

        string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Photos";


        Bitmap bm, bmOrg;
        byte Sobel = 240;
        int Contrast = 50;
        float enlargement = 0.4F;
        private Point RectStartPoint;

        private void SerieCrop_Load(object sender, EventArgs e)
        {
            this.Visible = false;

            using (Login login = new Login())
            {
                DialogResult dr = login.ShowDialog();
                if (dr == DialogResult.OK)
                {
                    this.Visible = true;

                    AppSession appSession = new AppSession();
                    AppSession.DataManager = new DataManager(login.ConnectionString);

                    InitCamera();

                }
                else
                    Application.Exit();
            }




            for (int i = 0; i < 255; i += 5)
                listBoxSobel.Items.Add(i);

            int index = listBoxSobel.FindString(Sobel.ToString());
            listBoxSobel.SetSelected(index, true);
            listBoxSobel.SelectedValueChanged += listBoxSobel_SelectedValueChanged;

            for (int i = 0; i < 100; i += 5)
                listBoxContrast.Items.Add(i);

            int index2 = listBoxContrast.FindString(Contrast.ToString());
            listBoxContrast.SetSelected(index2, true);
            listBoxContrast.SelectedValueChanged += listBoxContrast_SelectedValueChanged;

            btnAc.Click += btnAc_Click;
            checkBoxManuel.CheckedChanged += checkBoxManuel_CheckedChanged;

            btnKaydet.Click += btnKaydet_Click;

            splitContainerControl2.Panel1.MouseDown += Form1_MouseDown;
            splitContainerControl2.Panel1.MouseUp += Form1_MouseUp;


            //DataTable dt = AppSession.DataManager.ExecuteDataTable("GetAksSeriler2");
            //foreach (DataRow r in dt.Rows)
            //    comboBoxEdit1.Properties.Items.Add(r["AksSeriId"]);
            //comboBoxEdit1.Properties.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.DisableTextEditor;
            //comboBoxEdit1.SelectedIndexChanged += comboBoxEdit1_SelectedIndexChanged;

            chkSeri.CheckedChanged += chkSeri_CheckedChanged;
            splitContainerControl2.Resize += SerieCrop_Shown;
            this.Shown += SerieCrop_Shown;
            splitContainerControl2.Panel1.Paint += Panel1_Paint;
            gridView1.RowStyle += gridView1_RowStyle;
            FillGV(0);
//menüde bu seriyi göster veya hepsini göster seçenekleri olsun. bs.Filter kullan, yeniden çekme veriyi!

            this.FormClosing += Seri_FormClosing;
        }


        BindingSource bs;
        void chkSeri_CheckedChanged(object sender, EventArgs e)
        {
            if (gridView1.GetFocusedRowCellValue("AksSeriId") != DBNull.Value)
            {
                int AksSeriId = (int)gridView1.GetFocusedRowCellValue("AksSeriId");
                bs.Filter = chkSeri.Checked ? "AksSeriId=" + AksSeriId.ToString() : string.Empty;
            }
        }

        private void InitCamera()
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            else
            {
                DirectoryInfo di = new DirectoryInfo(path);
                /*
                foreach (FileInfo fi in di.GetFiles())
                    fi.Delete();
                 */
            }

            CameraHandler = new SDKHandler();
            CameraHandler.DownloadCompleted += CameraHandler_DownloadCompleted;
            CameraHandler.CameraHasShutdown += CameraHandler_CameraHasShutdown;
            CameraHandler.ImageSaveDirectory = path;

            List<Camera> CamList = CameraHandler.GetCameraList();

            if (CamList.Count > 0)
            {
                Camera camera = CamList[0];
                this.Text = camera.Info.szDeviceDescription;
                CameraHandler.OpenSession(camera);

                CameraHandler.SetSetting(EDSDK.PropID_SaveTo, (uint)EDSDK.EdsSaveTo.Host);
                CameraHandler.SetCapacity();
            }
        }

        void CameraHandler_DownloadCompleted(string path)
        {
            fl = path;
            this.Text = Code.ToString();
            Image bmp = Bitmap.FromFile(path);

            GC.Collect();
            bm = new Bitmap(bmp);
            bmOrg = new Bitmap(bmp);
            lookInside = new Rectangle(10, 10, bm.Width - 20, bm.Height - 20);
            esle.Clear();

            Ciz();
            //pictureBox1.Image = bmp.CropFromCenter(500); 
            //pictureBox1.Image = bmp;

            //if (Code > 0)
            //    Kaydet(path);
            //else
            //    labelControl1.Text = "Beklemede...";
        }
        string fl;
        int Code = 0;

        void ri_EditValueChanging(object sender, DevExpress.XtraEditors.Controls.ChangingEventArgs e)
        {
            e.Cancel = ((bool)e.NewValue && (rect4.Width == 0));
        }


        void SerieCrop_EditValueChanged(object sender, EventArgs e)
        {
            if (gridView1.FocusedRowHandle > -1)
            {
                int AksesuarId = (int)gridView1.GetFocusedRowCellValue("AksesuarId");
                string Boy = (string)gridView1.GetFocusedRowCellValue("Boy");
                bool Connected = (bool)(sender as CheckEdit).EditValue;

                if (!Connected)
                {
                    if (esle.ContainsKey(AksesuarId))
                        esle.Remove(AksesuarId);
                }
                else
                {
                    A box = new A();
                    box.AksesuarId = AksesuarId;
                    box.rect = rect4;
                    box.Boy = Boy;
                    esle.Add(AksesuarId, box);
                    rect4 = new Rectangle();
                }

                splitContainerControl2.Panel1.Refresh();

            }
        }

        void SerieCrop_Shown(object sender, EventArgs e)
        {
            splitContainerControl2.SplitterPosition = splitContainerControl2.Width - 250;
        }

        private void FillGV(int AksSeriId)
        {
            DataSet d = AppSession.DataManager.ExecuteDataSet("GetAksSeri2", AksSeriId);
            d.Tables[0].TableName = "Aks";
            bs = new BindingSource(d, "Aks");
            gridControl1.DataSource = bs;
            //gridView1.MakeReadOnly("except Connected");
            gridView1.Columns["Connected"].ColumnEdit = new RepositoryItemCheckEdit();
            RepositoryItem ri = gridView1.Columns["Connected"].ColumnEdit;
            ri.EditValueChanged -= SerieCrop_EditValueChanged;
            ri.EditValueChanged += SerieCrop_EditValueChanged;
            ri.EditValueChanging -= ri_EditValueChanging;
            ri.EditValueChanging += ri_EditValueChanging;
            gridView1.BestFitColumns();
        }

        void gridView1_RowStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowStyleEventArgs e)
        {
            if (e.RowHandle > -1)
                if (gridView1.GetRowCellValue(e.RowHandle, "Connected") != null)
                    if (gridView1.GetRowCellValue(e.RowHandle, "Connected") != DBNull.Value)
                        if ((bool)gridView1.GetRowCellValue(e.RowHandle, "Connected"))
                            e.Appearance.Font = new Font(e.Appearance.Font, FontStyle.Bold);
        }




        Dictionary<int, A> esle = new Dictionary<int, A>();

        void Panel1_Paint(object sender, PaintEventArgs e)
        {
            base.OnPaint(e);
            if (bmOrg != null)
            {
                e.Graphics.ScaleTransform(enlargement, enlargement);
                e.Graphics.DrawImage(bmOrg, new Rectangle(0, 0, bmOrg.Width, bmOrg.Height));

                foreach (KeyValuePair<int, A> box in esle)
                {
                    //e.Graphics.DrawRectangle(new Pen(Color.Green, 2), box.Value.rect);
                    Color customColor = Color.FromArgb(70, Color.Black);
                    SolidBrush shadowBrush = new SolidBrush(customColor);
                    e.Graphics.FillRectangles(shadowBrush, new RectangleF[] { box.Value.rect });

                    Font drawFont = new Font("Courier", 24, FontStyle.Bold);
                    SolidBrush drawBrush = new SolidBrush(Color.Red);

                    StringFormat sf = new StringFormat();
                    sf.LineAlignment = StringAlignment.Far;
                    sf.Alignment = StringAlignment.Far;

                    e.Graphics.DrawString(box.Value.Boy.ToString(), drawFont, drawBrush, box.Value.rect, sf);
                }

                if (rect4 != null)
                    e.Graphics.DrawRectangle(new Pen(Color.Red, 2), rect4);
                
                //Derive your own class from Panel to set its DoubleBuffered property to true.
            }
        }



        void checkBoxManuel_CheckedChanged(object sender, EventArgs e)
        {
            listBoxContrast.Enabled = listBoxSobel.Enabled = !checkBoxManuel.Checked;
        }

        void btnKaydet_Click(object sender, EventArgs e)
        {
            byte[] Photo1, Photo2;
            foreach (KeyValuePair<int, A> box in esle)
            {
                bm = new Bitmap(bmOrg);
                Photo1 = ApplyAll(bm, box.Value.rect, 32);
                bm = new Bitmap(bmOrg);
                Photo2 = ApplyAll(bm, box.Value.rect, 2);
                StoreBlob2DataBase(box.Value.AksesuarId, Photo1, Photo2);
            }

            //TODO: grid'deki check'lerin de temizlenmesi lazım
        }


        private byte[] ApplyAll(Bitmap b, Rectangle cR, int katsayi)
        {
            using (Image objImage = (Image)b)
            {
                cR.Inflate(3, 3);   //3'er pixel genişlet her yönde!

                KalikoImage sharpimg = new KalikoImage(Crop(objImage, cR));
                if (katsayi == 32)
                    sharpimg = sharpimg.Scale(new FitScaling(32, 32));
                else
                    sharpimg.Resize(sharpimg.Width / 2, sharpimg.Height / 2);
                sharpimg.ApplyFilter(new UnsharpMaskFilter(1.2F, 0.5F, 20));   //threshold: http://www.damiensymonds.com.au/tut_usm.html
                using (MemoryStream mstr = new MemoryStream())
                {
                    sharpimg.SaveJpg(mstr, 90);
                    sharpimg.Dispose();
                    return mstr.ToArray();
                }
            }
        }


        public Image Crop(Image bmp, Rectangle cropRect)
        {
            Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(bmp, new Rectangle(0, 0, target.Width, target.Height),
                                 cropRect,
                                 GraphicsUnit.Pixel);
            }
            return (Image)target;
        }


        protected static void StoreBlob2DataBase(int AksesuarId, byte[] content1, byte[] content2)
        {
            SqlConnection con = new SqlConnection(AppSession.DataManager.ConnectionString);
            con.Open();
            try
            {
                SqlCommand insert = new SqlCommand("UpdAksPhoto2", con);
                insert.CommandType = CommandType.StoredProcedure;
                //"insert into AksesuarPhotos (AksesuarId, Photo1, Photo2) values (@id, @image1, @image2)", con);
                //"update AksesuarPhotos set Photo2 = @image where AksesuarId = @id", con);
                //"update AksesuarPhotos set Photo1 = @image where AksesuarId = @id", con);
                SqlParameter idParameter = insert.Parameters.Add("@AksesuarId", SqlDbType.Int);
                idParameter.Value = AksesuarId;
                //imageParameter.Size = content.Length;
                SqlParameter imageParameter1 = insert.Parameters.Add("@Photo1", SqlDbType.Binary);
                imageParameter1.Value = content1;
                imageParameter1.Size = content1.Length;
                SqlParameter imageParameter2 = insert.Parameters.Add("@Photo2", SqlDbType.Binary);
                imageParameter2.Value = content2;
                imageParameter2.Size = content2.Length;
                insert.ExecuteNonQuery();
            }
            finally
            {
                con.Close();
            }
        }


        int stage = 0;
        void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            RectStartPoint = new Point((int)(e.Location.X / enlargement), (int)(e.Location.Y / enlargement));
            stage = 1;
        }

        void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            if (stage > 0)
            {
                stage = 0;
                lookInside = new Rectangle(RectStartPoint, new Size((int)(e.Location.X / enlargement) - RectStartPoint.X, (int)(e.Location.Y / enlargement) - RectStartPoint.Y));
                Ciz();
            }
        }

        void listBoxSobel_SelectedValueChanged(object sender, EventArgs e)
        {
            Sobel = (byte)((int)listBoxSobel.SelectedItem);
            Ciz();
        }

        void listBoxContrast_SelectedValueChanged(object sender, EventArgs e)
        {
            bm = bmOrg.Clone() as Bitmap;
            Contrast = (byte)((int)listBoxContrast.SelectedItem);
            Ciz();
        }


        void btnAc_Click(object sender, EventArgs e)
        {
            //CameraHandler.TakePhoto();

            using (OpenFileDialog openFileDialog1 = new OpenFileDialog())
            {
                openFileDialog1.Filter = "All Files (*.*)|*.*";
                openFileDialog1.FilterIndex = 1;
                //openFileDialog1.Multiselect = true;

                if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    Ac(openFileDialog1.FileName);

            }
        }

        private void Ac(string fn)
        {
            if (fn != string.Empty)
            {
                GC.Collect();
                bm = new Bitmap(fn);
                bmOrg = new Bitmap(fn);
                lookInside = new Rectangle(10, 10, bm.Width - 20, bm.Height - 20);
                esle.Clear();

                Ciz();
            }
        }

        Rectangle rect4;
        Rectangle lookInside;
        private void Ciz()
        {
            if (lookInside.Width + lookInside.Height > 10)
            {
                //ContrastCorrection filter = new ContrastCorrection(checkBoxManuel.Checked ? 0: Contrast);
                //filter.ApplyInPlace(bm);

                //Grayscale filter2 = new Grayscale(0.2125, 0.7154, 0.0721);
                //bm = filter2.Apply(bm);

                rect4 = FindBoxSobel(bm, lookInside, (checkBoxManuel.Checked ? (byte)0 : Sobel));

                splitContainerControl2.Panel1.Refresh();
            }
        }


        public Rectangle FindBoxSobel(Bitmap originalImage, Rectangle lookInside, byte threshold)
        {

            Bitmap image = originalImage;
            try
            {
                //Convert if needed (makes an extra copy)
                if (image.PixelFormat != PixelFormat.Format24bppRgb &&
                    image.PixelFormat != PixelFormat.Format32bppArgb &&
                    image.PixelFormat != PixelFormat.Format32bppRgb)
                {
                    image = AForge.Imaging.Image.Clone(image, PixelFormat.Format24bppRgb);
                }

                //Crop if needed (makes an extra copy unless we converted too, then only 1 extra copy)
                if (!lookInside.Equals(new Rectangle(0, 0, image.Width, image.Height)))
                {
                    Bitmap oldImage = image;
                    try
                    {
                        image = new Crop(lookInside).Apply(image);
                    }
                    catch
                    {
                    }
                    finally
                    {
                        if (oldImage != originalImage) oldImage.Dispose(); //Dispose the cloned 
                    }
                }


                //Makes 1 more copy at 1/3rd the size, in grayscale
                Rectangle result = FindBoxSobel(image, threshold);
                return new Rectangle(lookInside.X + result.X, lookInside.Y + result.Y, result.Width, result.Height);


            }
            finally
            {
                if (image != originalImage) image.Dispose();
            }

        }

        public Rectangle FindBoxSobel(Bitmap rgb, byte threshold)
        {
            using (Bitmap gray = Grayscale.CommonAlgorithms.Y.Apply(rgb))
            {

                //Apply sobel operator to grayscale image
                new SobelEdgeDetector().ApplyInPlace(gray);
                //Threshold into black and white.
                new Threshold(threshold).ApplyInPlace(gray);
                //Trim only exact black pixels
                // lock source bitmap data
                BitmapData data = gray.LockBits(new Rectangle(0, 0, gray.Width, gray.Height), ImageLockMode.ReadOnly, gray.PixelFormat);
                try
                {
                    return FindBoxExactGrayscale(data, 0);
                }
                finally
                {
                    gray.UnlockBits(data);
                }
            }
        }

        public Rectangle FindBoxExactGrayscale(BitmapData sourceData, byte indexToRemove)
        {
            if (sourceData.PixelFormat != PixelFormat.Format8bppIndexed) throw new ArgumentOutOfRangeException("FindBoxExact only operates on 8-bit grayscale images");
            // get source image size
            int width = sourceData.Width;
            int height = sourceData.Height;
            int offset = sourceData.Stride - width;

            int minX = width;
            int minY = height;
            int maxX = 0;
            int maxY = 0;

            // find rectangle which contains something except color to remove
            unsafe
            {
                byte* src = (byte*)sourceData.Scan0;

                for (int y = 0; y < height; y++)
                {
                    if (y > 0) src += offset; //Don't adjust for offset until after first row
                    for (int x = 0; x < width; x++)
                    {
                        if (x > 0 || y > 0) src++; //Don't increment until after the first pixel.
                        if (*src != indexToRemove)
                        {
                            if (x < minX)
                                minX = x;
                            if (x > maxX)
                                maxX = x;
                            if (y < minY)
                                minY = y;
                            if (y > maxY)
                                maxY = y;
                        }
                    }
                }
            }

            // check
            if ((minX == width) && (minY == height) && (maxX == 0) && (maxY == 0))
            {
                minX = minY = 0;
            }

            return new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
        }

    }
}